﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Media.Animation;
using System.Diagnostics;
using System.Windows.Threading;
using ShaderEffects;
using myBoard.Framework.Effects;

namespace myBoard.Framework.Controls.Navigation
{
	/// <summary>
	/// Interaction logic for BreadcrumbExplorer.xaml
	/// </summary>
	public partial class BreadcrumbExplorer : UserControl, IWeakEventListener
	{
        /// <summary>
        /// 
        /// </summary>
        private ObservableCollection<IBreadcrumbExplorerEntity> _breadcrumbEntities;

        public ObservableCollection<IBreadcrumbExplorerEntity> BreadcrumbEntities
        {
            get { return _breadcrumbEntities; }
            set { _breadcrumbEntities = value; }
        }

        public IBreadcrumbExplorerEntity FirstEntity
        {
            get { return (IBreadcrumbExplorerEntity)GetValue(FirstEntityProperty); }
            set { SetValue(FirstEntityProperty, value); }
        }

        public Brush BreadcrumbBackground
        {
            get { return (Brush)GetValue(BreadcrumbBackgroundProperty); }
            set { SetValue(BreadcrumbBackgroundProperty, value); }
        }        

        public static readonly DependencyProperty FirstEntityProperty =
            DependencyProperty.Register("FirstEntity", typeof(IBreadcrumbExplorerEntity), typeof(BreadcrumbExplorer), new UIPropertyMetadata(FirstEntityChanged));

        public static readonly DependencyProperty BreadcrumbBackgroundProperty =
            DependencyProperty.Register("BreadcrumbBackground", typeof(Brush), typeof(BreadcrumbExplorer), new UIPropertyMetadata(BreadcrumbBackgroundChanged));

        private static void FirstEntityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                BreadcrumbExplorer sender = d as BreadcrumbExplorer;
                sender.Reset();
            }
        }

        private static void BreadcrumbBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadcrumbExplorer sender = d as BreadcrumbExplorer;
            sender._breadCrumb.Background = e.NewValue as Brush;
        }



        public Brush BreadcrumbBorder
        {
            get { return (Brush)GetValue(BreadcrumbBorderProperty); }
            set { SetValue(BreadcrumbBorderProperty, value); }
        }

        public static readonly DependencyProperty BreadcrumbBorderProperty =
            DependencyProperty.Register("BreadcrumbBorder", typeof(Brush), typeof(BreadcrumbExplorer), new UIPropertyMetadata(BreadcrumbBorderChanged));

        private static void BreadcrumbBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            BreadcrumbExplorer sender = d as BreadcrumbExplorer;
            sender._breadCrumb.BorderBrush = e.NewValue as Brush;
        }


        private Storyboard _scrollSB;

		public BreadcrumbExplorer()
		{
			this.InitializeComponent();
            _breadcrumbEntities = new ObservableCollection<IBreadcrumbExplorerEntity>();
            _entitiesControlsContainer.SizeChanged += new SizeChangedEventHandler(EntitiesControlsContainer_SizeChanged);
            _scrollSB = this.Resources["Scroll"] as Storyboard;
            _breadCrumb.SelectionChanged += new SelectionChangedEventHandler(BreadCrumb_SelectionChanged);
		}
        

        void BreadCrumb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_breadCrumb.SelectedItem != null)
            {
                IBreadcrumbExplorerEntity previousItem = e.RemovedItems as IBreadcrumbExplorerEntity;
                IBreadcrumbExplorerEntity selectedItem = _breadCrumb.SelectedItem as IBreadcrumbExplorerEntity;
                Scroll(previousItem, selectedItem);
            }
        }

        private void BreadcrumbEntityBt_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Button bt = sender as Button;
            IBreadcrumbExplorerEntity to = bt.DataContext as IBreadcrumbExplorerEntity;
            Scroll(_breadcrumbEntities[_breadcrumbEntities.Count-1] as IBreadcrumbExplorerEntity, to);
        }

        private void _breadcrumbEntityBt_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Button bt = sender as Button;
            IBreadcrumbExplorerEntity to = _breadcrumbEntities[_breadcrumbEntities.Count - 1];
            Scroll(bt.DataContext as IBreadcrumbExplorerEntity, to);
        }

        private void _breadcrumbEntityBt_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            IBreadcrumbExplorerEntity entity = ((FrameworkElement)sender).DataContext as IBreadcrumbExplorerEntity;
            _breadCrumb.SelectedItem = entity;
            
            int index = _breadcrumbEntities.IndexOf(entity);
            for (int i = index + 1; i < _breadcrumbEntities.Count; i++)
            {
                WEMNextEntitySelected.RemoveListener(_breadcrumbEntities[i], this); 
                //_breadcrumbEntities[i].IBreadcrumbExplorerNextEntitySelected -= FirstEntity_IBreadcrumbExplorerNextEntitySelected;
                _breadcrumbEntities[i].Dispose();                
                _breadcrumbEntities.RemoveAt(i);
                _entitiesControlsContainer.Children.RemoveAt(i);                
                i--;
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
        } 

        public void Scroll(IBreadcrumbExplorerEntity from, IBreadcrumbExplorerEntity to)
        {
            if (to == from || to == null)
                return;

            int indexDiff = -_breadcrumbEntities.IndexOf(to);
            double offset = indexDiff * this.ActualWidth;
            
            if (offset == _entitiesControlsContainer.Margin.Left)
                return;
            
            if (_entitiesControlsContainer.Effect == null)
            {
                _entitiesControlsContainer.Effect = new DirectionalBlur() { Angle = 0, BlurAmount = 0 };
            }

            Storyboard scrollSB = _scrollSB.Clone();
            foreach (Timeline timeline in scrollSB.Children)
            {
                switch (timeline.Name)
                {
                    case "MarginTimeline":
                        {
                            ThicknessAnimationUsingKeyFrames marginThicknessAnimation = timeline as ThicknessAnimationUsingKeyFrames;
                            marginThicknessAnimation.KeyFrames[0].Value = new Thickness(offset, 0, 0, 0);
                        }
                        break;

                    case "MotionblurAngleTimeline":
                        {
                            DoubleAnimationUsingKeyFrames angleAnimation = timeline as DoubleAnimationUsingKeyFrames;
                            angleAnimation.KeyFrames[0].Value = _entitiesControlsContainer.Margin.Left > offset ? Math.PI : -Math.PI;
                        }
                        break;

                    case "MotionblurAmountTimeline":
                        {
                            double coef = Math.Abs( (Math.Abs(_entitiesControlsContainer.Margin.Left) - Math.Abs(offset))/this.ActualWidth);
                            DoubleAnimationUsingKeyFrames amountAnimation = timeline as DoubleAnimationUsingKeyFrames;
                            amountAnimation.KeyFrames[0].Value = 0.0002 * coef;
                        }
                        break;
                }
            }
            scrollSB.Completed += scrollSB_Completed;
            this.BeginStoryboard(scrollSB);
        }

        void scrollSB_Completed(object sender, EventArgs e)
        {
            _entitiesControlsContainer.Effect = null;
        }

        void EntitiesControlsContainer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            foreach (FrameworkElement control in _entitiesControlsContainer.Children)
            {
                control.Height = _entitiesControlsContainer.ActualHeight;
                control.Width = this.ActualWidth;
            }
        }        

        public void Reset()
        {
            WEMNextEntitySelected.AddListener(FirstEntity, this);
            //FirstEntity.IBreadcrumbExplorerNextEntitySelected += FirstEntity_IBreadcrumbExplorerNextEntitySelected;
            _breadcrumbEntities.Clear();
            _breadcrumbEntities.Add(FirstEntity);
            Binding itemSourceBinding = new Binding();
            itemSourceBinding.Source = _breadcrumbEntities;
            _breadCrumb.SetBinding(ListBox.ItemsSourceProperty, itemSourceBinding);
            _entitiesControlsContainer.Children.Clear();
            _entitiesControlsContainer.Children.Add(FindControl(FirstEntity));            
            _breadCrumb.SelectedItem = FirstEntity;
        }

        /// <summary>
        /// Should be used when an external control wants to manually add an entity
        /// </summary>
        /// <param name="nextEntity"></param>
        public void AddEntity(IBreadcrumbExplorerEntity nextEntity)
        {
            FirstEntity_NextIBreadcrumbExplorerEntitySelected(nextEntity,true);
        }

        /// <summary>
        /// Should be used when an external control wants to manually add an entity
        /// </summary>
        /// <param name="nextEntity"></param>
        public void AddEntityWithoutScrolling(IBreadcrumbExplorerEntity nextEntity)
        {
            FirstEntity_NextIBreadcrumbExplorerEntitySelected(nextEntity,false);
        }

        void FirstEntity_IBreadcrumbExplorerNextEntitySelected(IBreadcrumbExplorerEntity source, IBreadcrumbExplorerEntity NextEntity)
        {
            FirstEntity_NextIBreadcrumbExplorerEntitySelected(NextEntity,true);
        }        

        void FirstEntity_NextIBreadcrumbExplorerEntitySelected(IBreadcrumbExplorerEntity entity, bool shouldAutoScroll)
        {
            if (!_breadcrumbEntities.Contains(entity))
                _breadcrumbEntities.Add(entity);

            FrameworkElement control = FindControl(entity);
            if (control != null && !_entitiesControlsContainer.Children.Contains(control))
            {
                control.Height = _entitiesControlsContainer.ActualHeight;
                control.Width = this.ActualWidth;
                _entitiesControlsContainer.Children.Add(control);
                WEMNextEntitySelected.AddListener(entity, this);                
                //entity.IBreadcrumbExplorerNextEntitySelected += FirstEntity_IBreadcrumbExplorerNextEntitySelected;
                if (shouldAutoScroll)
                {
                    _breadCrumb.SelectedItem = entity;
                    _scrollViewer.ScrollToRightEnd();
                }
            }
        }

        FrameworkElement FindControl(IBreadcrumbExplorerEntity entity)
        {
            foreach (FrameworkElement control in _entitiesControlsContainer.Children)
            {
                if (control.DataContext == entity)
                    return control;
            }
            return entity.GetControl();           
        }

        #region IWeakEventListener Members

        public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            if (managerType == typeof(WEMNextEntitySelected))
            {
                FirstEntity_NextIBreadcrumbExplorerEntitySelected(((BreadcrumbArgs)e).Data as IBreadcrumbExplorerEntity,true);
                return true;
            }
            return false;
        }

        #endregion
    }
}